#include "Configuration.h"
#include <stdio.h>
#include <stdlib.h>
#include <string>

using namespace std;

void ReadRule(TiXmlNode* pParent, vector<Operation> & operations);
int ReadAttributes(TiXmlElement* pElement);
void PrintAnomaly(vector<Operation> operations, string action);

void Configuration::setAddress(const string &address)
{
	this->address = address;
}

void Configuration::setPort(const char* portString)
{
	int port = atoi(portString);
	this->port = port;
}

void Configuration::setInterface(const char *val)
{
	interface = val;
}

void Configuration::setThreadCount(const char *val)
{
	threadCount = atoi(val);
}

unsigned short Configuration::getPort()
{
	return port;
}

const std::string &Configuration::getAddress() const
{
	return address;
}

const std::string &Configuration::getInterface() const
{
	return interface;
}

unsigned int Configuration::getThreadCount() const
{
	return threadCount;
}

const std::vector<Field> &Configuration::getFields() const
{
	return fields;
}

const std::vector<Anomaly> &Configuration::getAnomalies() const
{
	return anomalies;
}

bool Configuration::loadConfigurationFile(const char* ConfigurationFile)
{
	TiXmlDocument doc(ConfigurationFile);
	bool loadOk = doc.LoadFile();
	if (!loadOk) {
		printf("Failed to load file!\n");
	}

	TiXmlHandle hDoc(&doc);
	TiXmlElement* pElem;
	TiXmlNode *tmpChild;
	TiXmlHandle hRoot(0);
	string tmpValue;
	string tmpGetText;

	cout << "Loading host configuration..." << endl;

	//block:Host
	pElem = hDoc.FirstChild( "host" ).FirstChild().Element();
	if (!pElem)
		return false;

	do {
		if (!strcmp(pElem->Value(), "address"))
			setAddress(pElem->GetText());
		else if (!strcmp(pElem->Value(), "port"))
			setPort(pElem->GetText());

		pElem = pElem->NextSiblingElement();
	} while (pElem);

	cout << "Done. Will report anomalies to " << getAddress() << ":" << getPort() << "." << endl;
	cout << "Loading various configuration settings..." << endl;

	//block: Misc
	pElem = hDoc.FirstChild( "misc" ).FirstChild().Element();
	if (!pElem)
		return false;

	do {
		if (!strcmp(pElem->Value(), "threads"))
			setThreadCount(pElem->GetText());
		else if (!strcmp(pElem->Value(), "iface"))
			setInterface(pElem->GetText());

		pElem = pElem->NextSiblingElement();
	} while (pElem);

	cout << "Done. Will use " << getThreadCount() << " threads and listen on interface " << getInterface() << "." << endl;
	cout << "Loading fields..." << endl;

	//block: Fields
	pElem=hDoc.FirstChild( "fields" ).FirstChild().Element();
	while (pElem) {
		Field newField;
		tmpValue = pElem->Value();//"field"

		tmpChild = pElem->FirstChild();//name
		tmpValue = tmpChild->ToElement()->GetText();
		newField.name = tmpValue;

		tmpChild = tmpChild->NextSibling();//offset
		newField.offset = atoi(tmpChild->ToElement()->GetText());

		tmpChild = tmpChild->NextSibling();//length
		newField.length = atoi(tmpChild->ToElement()->GetText());

		tmpChild = tmpChild->NextSibling();//header
		tmpValue = tmpChild->ToElement()->GetText();
		newField.header = tmpValue;

		fields.push_back(newField);

		pElem = pElem->NextSiblingElement();
	}

	cout << "Done. Processed " << fields.size() << " fields." << endl;
#ifdef DEBUG
	for( int i = 0; i < fields.size(); i++ ) {
		cout << fields[i].name << "-" << fields[i].offset
				<< "-" << fields[i].length
				<< "-" << fields[i].header << endl;
	}
#endif	

	cout << "Loading anomalies..." << endl;

	// first Anomaly
	pElem=hDoc.FirstChild( "anomalies" ).FirstChild().Element();
	while (pElem) {
		Anomaly anomaly;
		Operation firstOperation;
		tmpChild = pElem->FirstChild(); // name
		anomaly.name = tmpChild->ToElement()->GetText();

		tmpChild = tmpChild->NextSibling(); //rule
		tmpValue = tmpChild ->ToElement()->Value(); //"rule"
		firstOperation.action = tmpValue;

		ReadRule(tmpChild, anomaly.operations);
#ifdef DEBUG
		PrintAnomaly(anomaly.operations, anomaly.name);
#endif
		anomalies.push_back(anomaly);

		pElem = pElem->NextSiblingElement();
	}

	cout << "Done. Processed " << anomalies.size() << " anomalies." << endl;

	return loadOk;
}

void ReadRule(TiXmlNode* pParent, vector<Operation> & operations)
{
	if ( !pParent ) return;

	TiXmlNode* pChild;
	TiXmlText* pText;
	Operation newOperation;
	int t = pParent->Type();

	switch ( t ) {
	case TiXmlNode::TINYXML_ELEMENT:
#ifdef DEBUG
		cout << "Element [" << pParent->Value() << "]" << endl;
#endif
		newOperation.action=pParent->Value();
		newOperation.operand.fieldname = "";
		newOperation.operand.value = 0;
		if (!strcmp(pParent->Value(), "fieldname")) { //oznacza koniec reguły, tworzymy objekt Operand
			Operand operand;
			operand.fieldname = pParent->ToElement()->GetText();
			pParent = pParent->NextSibling();
			string tt = pParent->Value();
			operand.value = atoi(pParent->ToElement()->GetText());
			newOperation.operand = operand;
		} else if (strcmp(pParent->Value(), "value")) {
			for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
				ReadRule(pChild, newOperation.operations);
		}
		operations.push_back(newOperation);
		break;
#ifdef DEBUG
	case TiXmlNode::TINYXML_TEXT:
		pText = pParent->ToText();
		cout << "Text: [" << pText->Value() << "]" << endl;
		break;
#endif
	default:
		break;
	}

	return;
}

void PrintAnomaly(vector<Operation> operations, string action)
{
	vector<Operation>::iterator iter1 = operations.begin();
	int i = 1;
	while( iter1 != operations.end()) {
		cout << action << "-" << i << ": " << iter1->action << endl;
		if (iter1->operand.fieldname != "") {
			cout << action << "OPERAND: FieldName:" << iter1->operand.fieldname << " Value:" << iter1->operand.value << endl;
		}
		PrintAnomaly(iter1->operations, action + "->" + iter1->action);
		iter1++;
		i++;
	}
}
